﻿
// 由 MipmapCreate() 叫用
// 產生各層的縮小圖片，直至 1*1
static void MipmapCreateX2(unsigned char **Mipmaps, unsigned int *WidthHeight, const unsigned int LevelNum,
                  const unsigned char *SrcMap, const unsigned int SrcWidth, const unsigned int SrcHeight, const unsigned int bpp)
{
  unsigned int Level = 1; // 從第 2 層開始建立，第一層為 0
  const unsigned char *PreSrcMap = SrcMap;
  unsigned int PreSrcWidth = SrcWidth;
  unsigned int PreSrcHeight = SrcHeight;

  while(Level < LevelNum)
  {
    bool Xodd = PreSrcWidth & 1;
    // bool Yodd = PreSrcHeight & 1;
    unsigned int Width = (PreSrcWidth>1)? PreSrcWidth/2 : 1;
    unsigned int Height = (PreSrcHeight>1)? PreSrcHeight/2 : 1 ;
    unsigned int NumberOfPixels = Width * Height;
    unsigned int n=0, X=0, Y=0;

    WidthHeight[Level * 2] = Width;
    WidthHeight[Level * 2 + 1] = Height;

    unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
    Mipmaps[Level] = Pixels;

    while(n < NumberOfPixels)
    {
      unsigned char *p = Pixels + n*bpp;
      const unsigned char *s = PreSrcMap + (Y*PreSrcWidth + X)*bpp;
      if(Y < PreSrcHeight-1 && X < PreSrcWidth-1)
      {
        for(unsigned int b = 0; b < bpp; ++b)
          p[b] = s[b]/4 + s[b+bpp]/4 + s[b+PreSrcWidth*bpp]/4 + s[b+PreSrcWidth*bpp+bpp]/4;
        X+=2;
        if(X == PreSrcWidth || (Xodd && X == PreSrcWidth-1))
        {
          X = 0; Y+=2;
        }
      }
      else if(X < PreSrcWidth-1)
      {
        for(unsigned int b = 0; b < bpp; ++b)
          p[b] = s[b]/2 + s[b+bpp]/2;
        X+=2;
      }
      else // if(Y < PreSrcHeight-1)
      {
        for(unsigned int b = 0; b < bpp; ++b)
          p[b] = s[b]/2 + s[b+PreSrcWidth*bpp]/2;
        //X=0;
        Y+=2;
      }
      ++n;
    }

    ++Level;
    PreSrcMap = Pixels;
    PreSrcWidth = Width;
    PreSrcHeight = Height;
  }
}

/*
  用 max(Width,Height) 來算有多少層

  log2() 為 2 的對數
  int() 為取整數部份

  if Ext == true
    2^(n+1) 比 2^n 多一層
    2^n + 1 比 2^n 多一層
    所以 2^n + 1 至 2^(n+1) 比 2^n 多一層

    int(log2(len))+1 層 (log2(len) 無小數)
        或
    int(log2(len))+1+1 層 (log2(len) 有小數)

  if Ext == false
    只計算 int(log2(len))+1 層
*/
unsigned int CalculateLevelNum(const unsigned int len)
{
  unsigned int LevelNum = 1;
  unsigned int Len = len;
  unsigned int t;
  while((t = Len >> 1))
  {
    ++LevelNum;
    Len = t;
  }

  return LevelNum;
}

// 長寬皆不能為 0，否則回覆 false
// SrcMap 須指向以 byte 為單位，為每個像素做分色的圖片
// bpp 表示每個像素的 byte 數，比如 rgba 為 4，rgb 為 3
bool MipmapCreate(unsigned char ***Mipmap, unsigned int **WidthHeight, unsigned int *LevelNum,
                  const unsigned char *SrcMap, const unsigned int SrcWidth, const unsigned int SrcHeight,
                  const unsigned int bpp)
{
  if(SrcWidth == 0 || SrcHeight == 0)
    return false;

  if(SrcWidth > SrcHeight)
    *LevelNum = CalculateLevelNum(SrcWidth);
  else
    *LevelNum = CalculateLevelNum(SrcHeight);

  unsigned int NumberOfPixels = SrcWidth * SrcHeight;

  *Mipmap = new unsigned char *[*LevelNum];
  *WidthHeight = new unsigned int[(*LevelNum) * 2];

  (*WidthHeight)[0] = SrcWidth;
  (*WidthHeight)[1] = SrcHeight;

  unsigned char *Pixels = new unsigned char[NumberOfPixels * bpp];
  (*Mipmap)[0] = Pixels;

  // 先複製第 1 層
  for(unsigned int n=0, X=0, Y=0; n < NumberOfPixels; ++n)
  {
    unsigned char *p = Pixels + n*bpp;
    const unsigned char *s = SrcMap + (X + Y * SrcWidth) * bpp;

    for(unsigned int b = 0; b < bpp; ++b)
      p[b] = s[b];

    if(++X == SrcWidth)
    {
      X = 0;
      ++Y;
    }
  }

  MipmapCreateX2(*Mipmap,*WidthHeight,*LevelNum,Pixels,SrcWidth,SrcHeight,bpp);


  return true;
}

// 用於正確的刪除 MipmapCreate() 建立的所有資料
void MipmapDelete(unsigned char **Mipmap, unsigned int *WidthHeight, unsigned int LevelNum)
{
  delete [] WidthHeight;

  for(unsigned int n = 0; n < LevelNum; ++n)
    delete [] Mipmap[n];

  delete [] Mipmap;
}
